package bqg

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"net/http"
	"os"
	"save-kindle/entity"
	"save-kindle/log"
	"save-kindle/source"
	"strings"
	"time"
)

// const name = "https://www.biquger.com/biquge/%s/"
const name = "https://m.bi02.cc/kan/%s/list.html"

type BqgSource struct {
	source.BookInfo
}

func NewBqgSource(webSite string) *BqgSource {
	return &BqgSource{source.BookInfo{
		WebSite: webSite,
	}}
}

func (book *BqgSource) NewBook(bookId, bookName string) {
	book.BookId, book.BookName = bookId, bookName
}

func (book BqgSource) GetArticle() {
	// 获取目录
	catalog, _ := book.GetCatalog()

	file, err := os.OpenFile(fmt.Sprintf("%s.txt", book.BookName), os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		log.PrintErr(err.Error())
	}
	defer file.Close()

	file.WriteString("\n")

	for i, article := range catalog {
		log.Println(i, article)
		art := &article
		art, _ = book.GetArticleContent(art)

		writeFile(file, article)
		//break
	}
}

func (book BqgSource) GetArticleM() {
	// 获取目录
	catalog, _ := book.GetCatalog()

	file, err := os.OpenFile(fmt.Sprintf("%s.txt", book.BookName), os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		log.PrintErr(err.Error())
	}
	defer file.Close()

	file.WriteString("\n")

	fmt.Println("总大小", len(catalog))

	// fixme 线程池大小
	pool := make(chan struct{}, 10)
	count := 0
	counter := make(chan struct{})
	go func() {
		for i := range catalog {
			pool <- struct{}{}
			go func(index int, art *entity.Article) {
				log.Println(index, *art)
				art, _ = book.GetArticleContent(art)
				<-pool
				counter <- struct{}{}
			}(i, &(catalog[i]))
			//break
		}
	}()

	for count != len(catalog) {
		select {
		case <-counter:
			count++
		}
	}

	for _, article := range catalog {
		writeFile(file, article)
	}
}

// GetCatalog 获取文章目录
func (book BqgSource) GetCatalog() ([]entity.Article, error) {
	bookUrl := fmt.Sprintf(name, book.BookId)
	request, _ := http.NewRequest("GET", bookUrl, nil)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		log.PrintErr(err.Error())
	}

	defer response.Body.Close()

	// 解析章节
	document, err := goquery.NewDocumentFromReader(response.Body)
	if err != nil {
		log.PrintErr(err.Error())
	}

	articles := make([]entity.Article, 0)

	// 获取列表
	document.Find("div.book_last").Each(func(i int, selection *goquery.Selection) {
		selection.Find("dd").Each(func(ii int, ddTag *goquery.Selection) {
			if ii == 0 {
				return
			}
			attr, exists := ddTag.Find("a").Attr("href")
			if exists {
				article := entity.Article{
					ArticleUrl:  attr,
					ArticleName: ddTag.Text(),
				}
				// log.Println(article)
				articles = append(articles, article)
			}
		})
	})
	return articles, nil
}

// getArticleContent 获取文章内容
func (book BqgSource) GetArticleContent(article *entity.Article) (*entity.Article, error) {
retry:
	request, _ := http.NewRequest("GET", fmt.Sprintf("https://m.bi02.cc%s", article.ArticleUrl), nil)
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		log.PrintErr(err.Error())
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		time.Sleep(1 * time.Second)
		log.PrintErr("retry", article)
		goto retry
	}

	document, err := goquery.NewDocumentFromReader(response.Body)
	if err != nil {
		log.PrintErr(err.Error())
	}
	content := ""
	content, _ = doGet(document)
	if content == "" {
		// 暂停1s进行重试
		log.PrintErr("retry", article)
		time.Sleep(750 * time.Millisecond)
		goto retry
	}

	// 判断是否有下一页
	var nextPageInfo = ""

getNextPage:
	nextPageInfo, document = checkNextPage(document, article.ArticleUrl)
	if nextPageInfo != "" {
		// 说明还有下一页
		content = content[:len(content)-1] + nextPageInfo
		goto getNextPage
	}

	//document.Find("a#pb_next").Each(func(i int, selection *goquery.Selection) {
	//	if i == 0 {
	//		attr, exists := selection.Attr("href")
	//		if exists && attr[strings.Index(article.ArticleUrl, ".")] == '_' {
	//			req, _ := http.NewRequest("GET", fmt.Sprintf("https://m.bi02.cc%s", attr), nil)
	//			resp, err := http.DefaultClient.Do(req)
	//			if err != nil {
	//				log.PrintErr(err.Error())
	//			}
	//			defer resp.Body.Close()
	//
	//			if resp.StatusCode == http.StatusOK {
	//				doc, _ := goquery.NewDocumentFromReader(resp.Body)
	//				c, _ := doGet(doc)
	//				content = content[:len(content)-1] + c
	//			}
	//		}
	//	}
	//})

	if content == "" {
		// 暂停1s进行重试
		log.PrintErr("retry", article)
		time.Sleep(750 * time.Millisecond)
		goto retry
	}
	article.ArticleContent = content
	return article, nil
}

// checkNextPage 判断是否有下一页
func checkNextPage(doc *goquery.Document, articleUrl string) (string, *goquery.Document) {
	content := ""
	var document *goquery.Document
	doc.Find("a#pb_next").Each(func(i int, selection *goquery.Selection) {
		if i == 0 {
			attr, exists := selection.Attr("href")
			index := strings.Index(articleUrl, ".")
			if exists && len(attr) > index && attr[index] == '_' {
				req, _ := http.NewRequest("GET", fmt.Sprintf("https://m.bi02.cc%s", attr), nil)
				resp, err := http.DefaultClient.Do(req)
				if err != nil {
					log.PrintErr(err.Error())
				}
				defer resp.Body.Close()

				if resp.StatusCode == http.StatusOK {
					document, _ = goquery.NewDocumentFromReader(resp.Body)
					content, _ = doGet(document)
				}
			}
		}
	})
	return content, document
}

func doGet(doc *goquery.Document) (string, error) {
	articleContent := ""
	doc.Find("div#chaptercontent").Each(func(i int, selection *goquery.Selection) {
		html, _ := selection.Html()
		html = strings.ReplaceAll(html, " <br/>", "<br/>")
		html = strings.ReplaceAll(strings.ReplaceAll(html, "　", ""), "<br/>", "\n")[2:]
		html = strings.ReplaceAll(html, "\n\n", "\n")
		html = strings.ReplaceAll(html, "请收藏：https://m.bi02.cc <p class=\"noshow\">（温馨提示：请关闭畅读或阅读模式，否则内容无法正常显示）</p>\n", "")
		articleContent = html
	})
	return articleContent, nil
}

// writeFile 写入文件
func writeFile(file *os.File, v entity.Article) {
	file.WriteString(v.ArticleName)
	file.WriteString("\n")
	file.WriteString("\n")
	file.WriteString(v.ArticleContent + "\n\n")
}
